package com.group.controller;

import com.alibaba.fastjson.JSON;
import com.group.configurations.GetHttpSessionConfig;
import com.group.service.UserService;
import com.group.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import pojo.entity.Message;
import org.springframework.stereotype.Component;
import pojo.entity.Records;
import pojo.entity.User;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket 聊天服务端
 *
 * @see ServerEndpoint WebSocket服务端 需指定端点的访问路径
 * @see Session   WebSocket会话对象 通过它给客户端发送消息
 */

@Controller
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfig.class)
public class WebSocketChatServer {

    @Autowired
    UserService userService;

    /**
     * 全部在线会话(用户名：session)
     */
    private static Map<String, Session> onlineSessions = new ConcurrentHashMap<>();
    /**
     * 客服会话池（sessionId：用户名）
     */
    private static Map<String, String> servicePool = new ConcurrentHashMap<>();
    /**
     * 客服会话池（sessionId：用户名）
     */
    private static Map<String, String> userPool = new ConcurrentHashMap<>();

    /**
     * 建立通信（双向建立）（连接者：被连接者）
     */
    private static Map<String, String> communication = new ConcurrentHashMap<>();

    /**
     * 当客户端打开连接：1.添加会话对象 2.更新在线人数
     */
    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        //获取httpSession
        HttpSession httpsession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
        User user = (User) httpsession.getAttribute("user");
        if (user!=null){
            int userStatus = user.getUserStatus();
            if (userStatus==9){
                //客服登录
                onlineSessions.put(user.getUserName(), session);
                servicePool.put(session.getId(),user.getUserName());
            }else {
                //用户登录
                if (servicePool.size()>0){
                    String key = servicePool.keySet().stream().findAny().get();
                    String value = servicePool.get(key);
                    System.out.println(user.getUserName()+":得到客服:"+value);
                    communication.put(user.getUserName(),value);
                    communication.put(value,user.getUserName());
                    servicePool.remove(key);
                    sendMessageToMyself(Message.jsonStr(Message.SPEAK, "系统消息", value+"客服小姐姐为您服务！", onlineSessions.size()),session);
                    System.out.println("空闲客服数："+servicePool.size());
                }else {
                    sendMessageToMyself(Message.jsonStr(Message.SPEAK, "系统消息", "抱歉！客服繁忙，请稍后重试！", onlineSessions.size()),session);
                }
                onlineSessions.put(user.getUserName(), session);
                userPool.put(session.getId(),user.getUserName());
            }
        }else {
            onlineSessions.put(session.getId(), session);
        }
        sendMessageToAll(Message.jsonStr(Message.ENTER, "", "", onlineSessions.size()),"");
    }

    /**
     * 当客户端发送消息：1.获取它的用户名和消息 2.发送消息给所有人
     * <p>
     * PS: 这里约定传递的消息为JSON字符串 方便传递更多参数！
     */
    @OnMessage
    public void onMessage(Session session, String jsonStr) {
        Message message = JSON.parseObject(jsonStr, Message.class);
        String username = message.getUsername();
        System.out.println(username+":发送消息...");

        sendMessageToOne(Message.jsonStr(Message.SPEAK, message.getUsername(), message.getMsg(), onlineSessions.size()),username);
    }

    /**
     * 当关闭连接：1.移除会话对象 2.更新在线人数
     */
    @OnClose
    public void onClose(Session session) {
        String service = servicePool.get(session.getId());
        String user = userPool.get(session.getId());
        if (service!=null){
            //总池移除客服
            onlineSessions.remove(service);
            //移出客服池
            servicePool.remove(session.getId());

            // TODO: 2021/1/27 移除会话池


        }else if (user!=null){
            //总池移除用户
            onlineSessions.remove(user);
            //移出用户池
            userPool.remove(session.getId());

            String serviceName = communication.get(user);

            if (serviceName!=null){
                // TODO: 2021/1/27 移除会话池
                communication.remove(user);
                communication.remove(serviceName);
                System.out.println("会话移除，会话池人数："+communication.size());

                //客服回归客服池
                Session serviceSession = onlineSessions.get(serviceName);
                servicePool.put(serviceSession.getId(),serviceName);
                System.out.println(serviceName+"回归客服池：空闲客服数"+servicePool.size());
            }
        }else {
            //普通用户
            onlineSessions.remove(session.getId());
        }
        System.out.println("会话结束!");
        sendMessageToAll(Message.jsonStr(Message.QUIT, "", "", onlineSessions.size()),"");
    }

    /**
     * 当通信发生异常：打印错误日志
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

    /**
     * 公共方法：发送信息给所有人
     */
    private static void sendMessageToAll(String msg,String username) {
        System.out.println("------------"+onlineSessions.size());
        onlineSessions.forEach((id, session) -> {
            try {
                session.getBasicRemote().sendText(msg);
            } catch (Exception e) {
                System.out.println("会话已关闭");
            }
        });
    }

    /**
     * 公共方法：发送信息给所有人
     */
    private static void sendMessageToMyself(String msg,Session session) {
        try {
            session.getBasicRemote().sendText(msg);
        } catch (Exception e) {
            System.out.println("会话已关闭");
        }
    }

    private static void sendMessageToOne(String msg,String username) {

        /**
         * 点对点发送（确保只有建立连接用户能收到消息）
         */
        String value = communication.get(username);
        if (value!=null){
            Session keySession = onlineSessions.get(username);
            Session valueSession = onlineSessions.get(value);
            try {
                keySession.getBasicRemote().sendText(msg);
                valueSession.getBasicRemote().sendText(msg);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }else {
            // TODO: 2021/1/27 未能建立连接
        }


        /*onlineSessions.forEach((id, session) -> {
            try {
                if (id.equals(username)){
                    session.getBasicRemote().sendText(msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });*/
    }
}
